#include <stdio.h>
#include <sys/types.h>


	#ifdef TIME_WITH_SYS_TIME
		#include <sys/time.h>
		#include <time.h>
	#else
		#ifdef TM_IN_SYS_TIME
			#include <sys/time.h>
		#else
			#include <time.h>
		#endif
	#endif
	#include <sys/socket.h>


#include <stdlib.h>
#include <signal.h>
#include <math.h>
#include <errno.h>
//Zakomentovat v originalu a skusit prelozit - Kde to zarve?
#ifdef HAVE_FLOAT_H
#include <float.h>
#endif
//Konec zakomentovani

#ifndef __USE_GNU
	#define __USE_GNU
#endif

#include <string.h>

//Zakomentovat v originalu a skusit prelozit - Kde to zarve?
#ifdef HAVE_SYS_SELECT_H
#include <sys/select.h>
#endif
//Konec zakomentovani

#ifdef __EMX__
#define INCL_DOS
#include <os2.h>
#endif

//#include "data.h"
#include "1client.h"
#include "net.h"
//#include "cfg.h"
//#include "hash.h"
//#include "time.h"
//#include "getopt.h"
//#include "math.h"
//#include "error.h"


unsigned short port=DEFAULT_PORT;  /* game port (not a gameport ;-) )*/
int fd;   /* socket */
unsigned long last_tick;
unsigned long last_player_left=0,last_packet_came=0;
struct sockaddr_in server;  /* server address */
int my_id = 492;
// list of players 
struct player_list
{
        struct player_list *next,*prev;
        struct player member;
}players;

void print_ip(unsigned char * txt,struct in_addr ip)
{
	unsigned int a;

	sprintf(txt,"%d",*((unsigned char *)&ip));
	for (a=1;a<sizeof(ip);a++)
		sprintf(txt+strlen(txt),".%d",((unsigned char *)&ip)[a]);
}

/* write a message to stdout or stderr */
void message(unsigned char *msg,int output)
{
	time_t t;
	struct tm tm;
	static unsigned char timestamp[64];

#ifdef WIN32
	if ( !consoleApp )
		return;
#endif
	
	t=time(0);
	tm=*(localtime(&t));
	
	/* time stamp is in format day.month.year hour:minute:second */
	snprintf(timestamp,64,"%2d.%2d.%d %02d:%02d:%02d  ",tm.tm_mday,tm.tm_mon+1,tm.tm_year+1900,tm.tm_hour,tm.tm_min,tm.tm_sec);
	switch (output)
	{
		case 1:
		printf("%s%s",timestamp,msg);
		fflush(stdout);
		break;

		case 2:
		fprintf(stderr,"%s%s",timestamp,msg);
		fflush(stderr);
		break;
	}
}

/* initialize socket */
void init_socket(void)
{
	printf ("NOOB\n");
	message ("SUX", 2);
	struct sockaddr_in server;
	fd=socket(PF_INET,SOCK_DGRAM,IPPROTO_UDP);
	if (fd<0)
	{
		//ERROR("Error: Can't create socket!\n");
		//EXIT(1);
		message ("SUCKASS! THE NOOBZORING SOCKET!",2);
		//exit(2);
	}

	server.sin_family=AF_INET;
	server.sin_port=htons(port);
	server.sin_addr.s_addr=INADDR_ANY;
	message ("initalizing socket",2);
	if (bind(fd,(struct sockaddr*)&server,sizeof(server)))
	{
		unsigned char msg[256];
		snprintf(msg,256,"Error: Can't socket to port %d!\n",port);
		message("FUCK!",2);
		//ERROR(msg);
		//EXIT(1);
		return;
	}
}

//////////////////DUMP START-----------------------------------------------

char * contact_server(int color,unsigned char *name)
{
	static unsigned char packet[256];
	int l=strlen(name)+1;
	int a,r;
	int min,maj;

        fd_set fds;
        struct timeval tv;
        tv.tv_sec=4;
        tv.tv_usec=0;
        FD_ZERO(&fds);
        FD_SET(fd,&fds);

	packet[0]=P_FUCK;
	packet[1]=0;
	packet[2]=VERSION_MAJOR;
	packet[3]=VERSION_MINOR;
	packet[4]=color;
	memcpy(packet+5,name,l);

	send_packet(packet,l+5,(struct sockaddr*)(&server),my_id,0);


        if (!select(fd+1,&fds,NULL,NULL,&tv))return "No reply within 4 seconds. Press ENTER.";

	if ((r=recv_packet(packet,256,0,0,1,0,0))<0)
	{
		if (errno==EINTR)return "Server hung up. Press ENTER.";
		else return "Connection error. Press ENTER.";
	}

	switch(*packet)
	{
		case P_PLAYER_REFUSED:
		switch(packet[1])
		{
			/*case E_INCOMPATIBLE_VERSION:
			return "Incompatible client version. Connection refused. Press Enter.";
*/
			default:
			return "Connection refused. Press ENTER.";
		}
		
		case P_PLAYER_ACCEPTED:/*
		my_id=get_int(packet+33);
		if (r<39){send_quit();return "Incompatible server version. Givin' up. Press Enter.";}
		maj=packet[37];
		min=packet[38];
		if (maj!=VERSION_MAJOR||min<MIN_SERVER_VERSION_MINOR)
		{send_quit();return "Incompatible server version. Givin' up. Press Enter.";}
		game_start_offset=get_time();
		game_start_offset-=get_long_long(packet+25);
		health=100;
		armor=0;
		for(a=0;a<ARMS;a++)
			ammo[a]=0;
		ammo[0]=weapon[0].basic_ammo;
		current_weapon=0;
		weapons=17; */ /* gun and grenades */
		//hero=new_obj(
		//	get_int(packet+1),   /* ID */
		//	T_PLAYER,   /* type */
		//	0,  /* time to live */
		//	get_int16(packet+5),   /* sprite */
		//	0,        /* position */
		//	get_int16(packet+23),        /* status */
		//	get_float(packet+7),     /* X */
		//	get_float(packet+11),    /* Y */
		//	get_float(packet+15),    /* XSPEED */
		//	get_float(packet+19),    /* YSPEED */
		//	0
		//	);
		break;
		
		default:
		return "Connection error. Press ENTER.";
	}
	return 0;
}

/* find address of server and fill the server address structure */
char * find_server(char *name,unsigned short port)
{
	struct hostent *h;
	
	h=gethostbyname(name);
	if (!h)return "Error: Can't resolve server address.";

	server.sin_family=AF_INET;
	server.sin_port=htons(port);
	server.sin_addr=*((struct in_addr*)(h->h_addr_list[0]));
	return 0;
}

//make the server print some FUCK
void connect() {
	char p;
	char *m;
	*p=strtol(port,0,10);
	m=find_server(host,*p);
	m=init_socket();
	m=contact_server(*color,name);
}
/////////////DUMP END -----------------------------------------------------

void send_chuck_to_player(struct player *player)
{
	static unsigned char p[MAX_PACKET_LENGTH];

	if (!(player->packet_pos))return;
	if (player->packet_pos>MAX_PACKET_LENGTH-1)return;
	p[0]=P_CHUNK;
	memcpy(p+1,player->packet,player->packet_pos);
	send_packet(p,(player->packet_pos)+1,(struct sockaddr*)(&(player->address)),0,player->id);
	player->packet_pos=0;
}


void send_chuck_packet_to_player(unsigned char *packet, int len, struct player *player)
{
	if (len>MAX_PACKET_LENGTH-1)return;
	if ((player->packet_pos)+len>MAX_PACKET_LENGTH-1)send_chuck_to_player(player);
	memcpy((player->packet)+(player->packet_pos),packet,len);
	player->packet_pos+=len;
}


void send_chucks(void)
{
	struct player_list* p;

	for (p=&players;p->next;p=p->next)
 		send_chuck_to_player(&(p->next->member));
}


/* send a packet to all players except one */
/* if not_this_player is null, sends to all players */
void sendall(unsigned char *packet,int len, struct player * not_this_player)
{
	struct player_list* p;

	if (!not_this_player)
		for (p=&players;p->next;p=p->next)
 			send_packet(packet,len,(struct sockaddr*)(&(p->next->member.address)),0,p->next->member.id);
	else
		for (p=&players;p->next;p=p->next)
			if ((&(p->next->member))!=not_this_player)
 				send_packet(packet,len,(struct sockaddr*)(&(p->next->member.address)),0,p->next->member.id);
}


/* send a packet to all players except one */
/* if not_this_player is null, sends to all players */
void sendall_chucked(unsigned char *packet,int len, struct player * not_this_player)
{
	struct player_list* p;

	if (!not_this_player)
		for (p=&players;p->next;p=p->next)
 			send_chuck_packet_to_player(packet,len,&(p->next->member));
	else
		for (p=&players;p->next;p=p->next)
			if ((&(p->next->member))!=not_this_player)
 				send_chuck_packet_to_player(packet,len,&(p->next->member));
}




/* send update status packet to all players (except not_this_player if this is !NULL)*/
void sendall_update_status(struct it* obj, struct player * not_this_player)
{
	struct player_list* p;
	static unsigned char packet[8];

	packet[0]=P_UPDATE_STATUS;
	//put_int(packet+1,obj->id);
	//put_int16(packet+5,obj->status);
	
	if (!not_this_player)
		for (p=&players;p->next;p=p->next)
 			send_chuck_packet_to_player(packet,7,&(p->next->member));
	else
		for (p=&players;p->next;p=p->next)
			if ((&(p->next->member))!=not_this_player)
 				send_chuck_packet_to_player(packet,7,&(p->next->member));
}



/* send message to a player */
/* name is name of player who sent the message (chat), NULL means it's from server */
void send_message(struct player* player,unsigned char *name,unsigned char *msg)
{
	static unsigned char packet[256];
	int len;

	packet[0]=P_MESSAGE;
	if (!name){snprintf(packet+1,256,"%s",msg);len=strlen(msg)+1+1;}
	else {snprintf(packet+1,256,"%s> %s",name,msg);len=strlen(name)+strlen(msg)+1+3;}
	send_chuck_packet_to_player(packet,len,player);
}

void sendall_bell(void)
{
	static unsigned char packet;
	struct player_list* p;

	packet=P_BELL;
	for (p=&players;p->next;p=p->next)
 		send_chuck_packet_to_player(&packet,1,&(p->next->member));

}





void free_all_memory(void)
{
	struct queue_list *t;
	struct player_list *p;
}

/* fatal signal handler (sigsegv, sigabrt, ... ) */
void signal_handler(int sig_num)
{
	unsigned char packet[16];
	unsigned char txt[256];
	
	packet[0]=P_END;
	memcpy(packet+1,"server",7);

	sendall(packet,8,0);
	sendall(packet,8,0);
	sendall(packet,8,0);
	sendall(packet,8,0);
	sendall(packet,8,0);
	sendall(packet,8,0);
	sendall(packet,8,0);
	sendall(packet,8,0);
	/* 800 % redundancy should be enough ;-) */

	snprintf(txt,256,"Signal %d caught.\n",sig_num);
	message(txt,2);
	free_all_memory();
	
#ifdef WIN32
	hServerExitEvent=1;
#else
	signal(sig_num,SIG_DFL);
	raise(sig_num);
#endif
}







/*-----------------------------------------------------------------------------------*/
int server(void)
{
	int a;
	unsigned char txt[256];
	unsigned long last_time;
	//unsigned char *LEVEL;
	
	//last_player=&players;
	//last_obj=&objects;
	
	snprintf(txt,256,"Running 0verkill server version %d.%d\n",0,0);
	message(txt,2);

	message("Initialization.\n",2);

	
//	hash_table_init(); //hash table sucks


	message("Not loading sprites.\n",2);
	message("Loading level graphics.\n",2);
	message("Loading level map.\n",2);

	message("Initializing socket-dfgsuck.\n",2);
	init_socket();  /* initialize socket */
	
	message("Installing signal handlers.\n",2);
	signal(SIGINT,signal_handler);
	signal(SIGTERM,signal_handler);
	signal(SIGFPE,signal_handler);
	signal(SIGILL,signal_handler);
	signal(SIGABRT,signal_handler);

	message("Game started.\n",2);

#ifdef __EMX__
	DosSetPriority(PRTYS_PROCESS, PRTYC_FOREGROUNDSERVER, 1, 0);
#endif

	last_time=get_time();
	while (1) {
		last_time+=PERIOD_USEC;
		if (get_time()-last_time>PERIOD_USEC*100)last_time=get_time();
		send_chucks();
		last_tick=get_time();
		sleep_until(last_time+PERIOD_USEC);
	}
 
	return 0;
}


int main(int argc, char **argv)
{
	int a;



	
	a=server();
	free_all_memory();
	
	return a;
}
